/*
 * Graph CLASS:
 * This class presents concept of DIRECTED/UNDIRECTED graph represented by 
 * INCIDENCE LIST.
 *
 */

#ifndef UNITRAF_GRAPHTRAITS_GRAPH_HPP
#define UNITRAF_GRAPHTRAITS_GRAPH_HPP

#include <graph\traits\IncidenceList.hpp>


namespace unitraf {

namespace graph_traits {

///////////////////////////////////////////////////////////////////////////////

// Graph traits set
template<class _VertexProperty, class _EdgeProperty, class _Model, class _Directed> 
  struct GraphTraits;

  // Traits for DIRECTED graph implemented as INCIDENCE LIST
  template<class _VertexProperty, class _EdgeProperty>
    struct GraphTraits<_VertexProperty, _EdgeProperty, incidence_list_tag, directed_tag> {
    
      typedef IncidenceList<_VertexProperty, _EdgeProperty, directed_tag> model_type;

      typedef typename model_type::vertex_descriptor vertex_descriptor;
      typedef typename model_type::vertex_type vertex_type;
      typedef typename model_type::edge_descriptor edge_descriptor;
      typedef typename model_type::edge_type edge_type;

  };

  
///////////////////////////////////////////////////////////////////////////////


// See comment at the top of the file
template<class _VertexProperty, class _EdgeProperty, class _Model, class _Directed> 
  class Graph {

   public:
    ///////////////////////////////////////////////////////////////////////////
    
    typedef GraphTraits<_VertexProperty, _EdgeProperty, _Model, _Directed> traits;

    typedef typename traits::vertex_descriptor vertex_descriptor;
    typedef typename traits::vertex_type vertex_type;
    typedef typename traits::edge_descriptor edge_descriptor;
    typedef typename traits::edge_type edge_type;
    typedef typename traits::model_type model_type;

    /////////////////////////////////////////////////////////////////////////////
    // CONSTRUCTORS AND INITIALIZERS
    Graph() {};
    ~Graph() {};
  
    // Initialize by the edges' list
    template<class _EdgeIter, class _VertexIter> Graph(_VertexIter first_vertex, 
      _VertexIter last_vertex, _EdgeIter first_edge, _EdgeIter last_edge) 
        : model_(first_vertex, last_vertex, first_edge, last_edge) {};

    // REGULAR
    // METHODS

    // Insert given vertices' sequence 
    template<class _VertexIter>
      void InsertVertices(_VertexIter first, _VertexIter last) {
        return model_._Vinsert(first, last);
      };
    
    // Insert given edges' sequence 
    template<class _EdgeIter>
      void InsertEdges(_EdgeIter first, _EdgeIter last) {
        return model_._Einsert(first, last);
      };

    // Returns itertor for edge given its { source, target } vertices
    typename model_type::vertex_vi GetVertex(const vertex_descriptor& vertex) const {
        return model_._get_vertex(vertex);
    };

    // Returns iterator edge given its { source, target } vertices
    typename model_type::edge_vi GetEdge(const vertex_descriptor& source,
      const vertex_descriptor& target) const {
        return model_._get_edge(source, target);
    };

    // Returns iterators into sequence of vertices
    typename model_type::vertex_pairii GetVertices() const {
      return model_._get_vertices();
    };

    // Returns iterators into sequence of vertices with positive out-degree
    typename model_type::out_vertex_pairii 
      GetOutVertices() const {
        return model_._get_out_vertices();
    };

    // Returns iterators into sequence of edges outgoing from given vertex
    typename model_type::out_edge_pairii 
      GetOutEdges(const vertex_descriptor& vertex) const {
        return model_._get_outgoing_edges(vertex);
    };

    // Returns iterators into sequence of vertices reachable from given vertex
    typename model_type::reachable_vertex_pairii 
      GetReachableVertices(const vertex_descriptor& vertex) const {
        return model_._get_reachable_vertices(vertex);
    };

    // Check integrity of graph underlying model
    bool _check_integrity() const { return model_._check_integrity(); };

        
   private:
    Graph(Graph&&);       /* NOT DEFINED! */
    Graph(const Graph&);  /* NOT DEFINED! */

    // Graph (primary) model
    model_type model_;

  };


};  // namespace graph_traits

};  // namespace unitraf

#endif  // #ifndef UNITRAF_GRAPHTRAITS_GRAPH_HPP
